package web

import (
	"errors"
	"fmt"
	"gitee.com/DonHz/basic-go/webook/internal/service"
	"gitee.com/DonHz/basic-go/webook/internal/service/oauth2/wechat"
	ijwt "gitee.com/DonHz/basic-go/webook/internal/web/jwt"
	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
	uuid "github.com/lithammer/shortuuid/v4"
	"net/http"
	"time"
)

type OAuth2WechatHandler struct {
	svc wechat.Service
	userSvc service.UserService
	ijwt.Handler
	cfg      WechatHandlerConfig
	stateKey []byte
}

type WechatHandlerConfig struct {
	Secure bool
}

func NewOAuth2WechatHandler(svc wechat.Service, userSvc service.UserService,
	cfg WechatHandlerConfig, jwtHandler ijwt.Handler) *OAuth2WechatHandler {
	return &OAuth2WechatHandler{
		svc: svc,
		userSvc: userSvc,
		cfg: cfg,
		stateKey: []byte("qJfZR1psrw512321T2aPbeRXUl0eLtdasda2bcFobbf9MKhdbd8MoR2V046H0obQd2tc"),
		Handler: jwtHandler,
	}
}


func (h *OAuth2WechatHandler) RegisterRoutes(server *gin.Engine) {
	wechat:=server.Group("/oauth2/wechat")
	wechat.GET("/authurl", h.AuthURL)
	wechat.Any("/callback", h.Callback)
}

func (h *OAuth2WechatHandler) AuthURL(ctx *gin.Context) {
	state:=uuid.New()
	url, err:=h.svc.AuthURL(ctx, state)
	// 储存一下 state

	if err!=nil {
		ctx.JSON(http.StatusOK, Result{
			Code: 200,
			Msg: "获取扫码登录的URL失败",
		})
	}
	// 同web/jwt.go文件中
	token:=jwt.NewWithClaims(jwt.SigningMethodES256, StateClaims{
		State: state,
		RegisteredClaims:jwt.RegisteredClaims{
			// 过期时间
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Minute * 5)),
		},
	})
	tokenStr, err:=token.SignedString(h.stateKey)
	if err!=nil {
		ReturnError(ctx,5,"系统错误")
		return
	}
	ctx.SetCookie("jwt-state",tokenStr, 300,
		"/oauth2/wechat/callback", "", h.cfg.Secure, true)
	ReturnSuccess(ctx, 200, "获取成功", url, 1)
}



func (h *OAuth2WechatHandler) Callback(ctx *gin.Context) {
	code:=ctx.Query("code")
	err:= h.verifyState(ctx)
	if err!=nil{
		ReturnError(ctx, 5, "登陆失败")
		return
	}
	info, err := h.svc.VerifyCode(ctx, code)
	if err != nil {
		ReturnError(ctx, 5, "系统异常")
		return
	}
	user, err := h.userSvc.FindOrCreateByWechat(ctx, info)
	if err != nil {
		ReturnError(ctx, 5, "系统异常")
	}
	err = h.SetLoginToken(ctx, user.Id)
	if err != nil {
		ReturnError(ctx, 5, "系统异常")
	}

	ReturnSuccess(ctx, 0, "OK", "", 1)
}

func (h *OAuth2WechatHandler) verifyState(ctx *gin.Context) error {
	state := ctx.Query("state")
	// 这里校验一下 state
	// 取出请求种的cookie
	ck, err := ctx.Cookie("jwt-state")
	if err != nil {
		ReturnError(ctx, 4, "登陆失败")
		return fmt.Errorf("拿不到state的cookie，err: %w",err)
	}

	var sc StateClaims
	token, err := jwt.ParseWithClaims(ck, &sc, func(token *jwt.Token) (interface{}, error) {
		return h.stateKey, nil
	})
	if err != nil || !token.Valid {
		ReturnError(ctx, 4, "登陆失败")
		return fmt.Errorf("token 过期，err: %w",err)
	}
	if sc.State != state {
		ReturnError(ctx, 4, "登陆失败")
		return errors.New("state不相等")
	}
	return nil
}

type StateClaims struct {
	State string
	jwt.RegisteredClaims
}